package com.cysyz.mylib.jbpm.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.zip.ZipInputStream;

import org.jbpm.api.ProcessDefinition;
import org.jbpm.api.ProcessDefinitionQuery;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.TaskQuery;
import org.jbpm.api.history.HistoryProcessInstance;
import org.jbpm.api.history.HistoryTask;
import org.jbpm.api.task.Participation;
import org.jbpm.api.task.Task;

import com.cysyz.mylib.jbpm.IJBPMProcessEnginSimpleOperator;

public class JBPMProcessEngineSimpleOperateImpl implements
		IJBPMProcessEnginSimpleOperator {

	/** 流程引擎 */
	private ProcessEngine processEngine;

	public ProcessEngine getProcessEngine() {
		return processEngine;
	}

	public void setProcessEngine(ProcessEngine processEngine) {
		this.processEngine = processEngine;
	}

	public JBPMProcessEngineSimpleOperateImpl() {
		super();
	}

	public JBPMProcessEngineSimpleOperateImpl(ProcessEngine processEngine) {
		super();
		this.processEngine = processEngine;
	}

	public String deploymentProcessDefinitionByClassPathZip(String fileName) {
		InputStream in = this.getClass().getClassLoader()
				.getResourceAsStream(fileName);
		return deploymentProcessDefinitionByClassPathZip0(in);
	}

	public String deploymentProcessDefinitionByClassPathZip(File file)
			throws FileNotFoundException {
		InputStream in = new FileInputStream(file);
		return deploymentProcessDefinitionByClassPathZip0(in);
	}

	private String deploymentProcessDefinitionByClassPathZip0(InputStream in) {
		ZipInputStream zipInputStream = new ZipInputStream(in);
		String deploymentId = processEngine.getRepositoryService()// 管理流程定义和部署对象
				.createDeployment()// 创建部署对象
				.addResourcesFromZipInputStream(zipInputStream)// 可以一次部署多个文件
				.deploy();// 完成部署
		return deploymentId;
	}

	public String deploymentProcessDefinitionByClassPathFile(String fileName) {
		String deploymentId = processEngine.getRepositoryService()// 管理流程定义和部署对象
				.createDeployment()// 创建部署对象
				.addResourceFromClasspath(fileName)// 从类路径部署资源文件，一次只能部署一个资源
				.deploy();// 完成部署
		return deploymentId;
		// System.out.println("部署对象ID："+deploymentId);
	}

	public List<ProcessDefinition> findProcessDefinitionList(
			ProcessDefintionQueryConds conds) {
		ProcessDefinitionQuery processDefinitionQuery = configProcessDefinition0(conds);
		return processDefinitionQuery.list();
	}

	public ProcessDefinition findProcessDefinition(
			ProcessDefintionQueryConds conds) {
		ProcessDefinitionQuery processDefinitionQuery = configProcessDefinition0(conds);
		return processDefinitionQuery.uniqueResult();
	}

	public long findProcessDefinitionListCount(ProcessDefintionQueryConds conds) {
		ProcessDefinitionQuery processDefinitionQuery = configProcessDefinition0(conds);
		return processDefinitionQuery.count();
	}

	private ProcessDefinitionQuery configProcessDefinition0(
			ProcessDefintionQueryConds conds) {
		ProcessDefinitionQuery processDefinitionQuery = processEngine
				.getRepositoryService()// 管理流程定义和部署对象
				.createProcessDefinitionQuery();// 创建流程定义的查询对象

		Set<Entry<ProcessDefinitionCondsType, String>> entrySet = conds
				.getQueryConds().entrySet();

		for (Entry<ProcessDefinitionCondsType, String> condTypeAndValue : entrySet) {
			condTypeAndValue.getKey().setCond(processDefinitionQuery,
					condTypeAndValue.getValue());
		}

		Map<ProcessDefinitionQueryOrderType, ProcessDefintionProperty> orders = conds
				.getOrders();

		Set<Entry<ProcessDefinitionQueryOrderType, ProcessDefintionProperty>> orderTypeAndValueEntrySet = orders
				.entrySet();
		for (Entry<ProcessDefinitionQueryOrderType, ProcessDefintionProperty> orderTypeAndValue : orderTypeAndValueEntrySet) {
			orderTypeAndValue.getKey().setOrder(processDefinitionQuery,
					orderTypeAndValue.getValue());
		}

		PageInfo pageInfo = conds.getPageInfo();
		if (pageInfo != null) {
			processDefinitionQuery.page(pageInfo.getFirstResult(),
					pageInfo.getMaxResults());
		}

		return processDefinitionQuery;
	}

	public List<Task> findMyPersonalTaskList(TaskQueryConds conds) {
		TaskQuery taskQuery = configTaskQuery0(conds);
		return taskQuery.list();
	}

	public Task findMyPersonalTask(TaskQueryConds conds) {
		TaskQuery taskQuery = configTaskQuery0(conds);
		return taskQuery.uniqueResult();
	}

	public long findMyPersonalTaskListCount(TaskQueryConds conds) {
		TaskQuery taskQuery = configTaskQuery0(conds);
		return taskQuery.count();
	}

	private TaskQuery configTaskQuery0(TaskQueryConds conds) {
		TaskQuery taskQuery = processEngine.getTaskService()// 管理任务的Service
				.createTaskQuery();// 创建一个任务查询对象
		Set<Entry<TaskCondsType, String>> condTypeAndValueEntrySet = conds
				.getQueryConds().entrySet();
		for (Entry<TaskCondsType, String> condTypeAndValue : condTypeAndValueEntrySet) {
			condTypeAndValue.getKey().setCond(taskQuery,
					condTypeAndValue.getValue());
		}

		Set<Entry<TaskQueryOrderType, TaskProperty>> orderTypeAndValueEntrySet = conds
				.getOrders().entrySet();
		for (Entry<TaskQueryOrderType, TaskProperty> orderTypeAndValue : orderTypeAndValueEntrySet) {
			orderTypeAndValue.getKey().setOrder(taskQuery,
					orderTypeAndValue.getValue());
		}

		PageInfo pageInfo = conds.getPageInfo();
		if (pageInfo != null) {
			taskQuery.page(pageInfo.getFirstResult(), pageInfo.getMaxResults());
		}
		return taskQuery;
	}

	public List<HistoryTask> historyTask(String userId) {
		return processEngine.getHistoryService()//
				.createHistoryTaskQuery()//
				.assignee(userId)//
				.list();
	}

	public List<HistoryProcessInstance> historyProcessInstance(
			String processInstanceId) {
		return processEngine.getHistoryService()//
				.createHistoryProcessInstanceQuery()//
				.processInstanceId(processInstanceId).list();
	}

	public void startProcessInstanceByKey(String key,
			Map<String, ?> processVariableMap) {
		processEngine.getExecutionService()// 管理执行对象和流程实例
				.startProcessInstanceByKey(key, processVariableMap);// 使用流程定义的key启动流程实例，优势：默认是启动最新版本的流程定义
	}

	public void startProcessInstanceByKey(String key) {
		processEngine.getExecutionService()// 管理执行对象和流程实例
				.startProcessInstanceByKey(key);// 使用流程定义的key启动流程实例，优势：默认是启动最新版本的流程定义
	}

	public void completeTask(String taskId) {
		processEngine.getTaskService()// 管理任务的Service
				.completeTask(taskId);// 指定任务ID完成任务

	}

	public void completeTask(String taskId, String outcome) {
		processEngine.getTaskService()//
				.completeTask(taskId, outcome);// 使用任务ID和指定连线的名称完成任务
		System.out.println("完成任务：任务ID：" + taskId);
	}

	public void signalExecution(String executionId) {
		processEngine.getExecutionService()// 与执行对象和流程实例相关的Service
				.signalExecutionById(executionId);
	}

	public void signalExecution(String executionId, String outcome) {
		processEngine.getExecutionService()// 与执行对象和流程实例相关的Service
				.signalExecutionById(executionId, outcome);
	}

	public void setVariable(String executionId, String key, Object value) {
		processEngine.getExecutionService()
				.setVariable(executionId, key, value);
	}

	public void setVariables(String executionId, Map<String, ?> variables) {
		processEngine.getExecutionService()
				.setVariables(executionId, variables);
	}

	public Object getVariable(String executionId, String key) {
		return processEngine.getExecutionService()
				.getVariable(executionId, key);
	}

	public Map<String, Object> getVariables(String executionId,
			Set<String> variableNames) {
		return processEngine.getExecutionService().getVariables(executionId,
				variableNames);
	}

	public Map<String, Object> getVariables(String executionId) {
		Set<String> variableNames = processEngine.getExecutionService()
				.getVariableNames(executionId);
		return processEngine.getExecutionService().getVariables(executionId,
				variableNames);
	}

	public void takeTask(String taskId, String userId) {
		processEngine.getTaskService().takeTask(taskId, userId);
	}

	public void assignTask(String taskId, String userId) {
		processEngine.getTaskService().assignTask(taskId, userId);
	}

	public void assignTask(String taskId) {
		processEngine.getTaskService().assignTask(taskId, null);
	}

	public void addPaticipation(String taskId, String userId) {
		processEngine.getTaskService().addTaskParticipatingUser(taskId, userId,
				Participation.CANDIDATE);
	}

	public void removePaticipation(String taskId, String userId) {
		processEngine.getTaskService().removeTaskParticipatingUser(taskId,
				userId, Participation.CANDIDATE);
	}

	public InputStream findImage(String deploymentId, String resourceName) {
		// 从工作流的表中获取资源图片的输入流
		return processEngine.getRepositoryService().getResourceAsStream(
				deploymentId, resourceName);
	}

	public void deleteProcessDefinition(String deploymentId) {
		/**
		 * deleteDeployment:不带级联的删除 *
		 * 如果一个流程没有启动，说明流程正在执行，此时可以使用deleteDeployment方法进行删除 *
		 * 但是如果一个流程已经启动，此时不可以使用deleteDeployment方法进行删除，否则会抛出异常
		 */
		// processEngine.getRepositoryService()//管理流程定义和部署对象
		// .deleteDeployment(deploymentId);//使用部署ID进行删除
		/**
		 * deleteDeploymentCascade:带级联的删除（项目中使用） * 不管流程是否正在执行，都能删除对应的数据
		 */
		processEngine.getRepositoryService()// 管理流程定义和部署对象
				.deleteDeploymentCascade(deploymentId);// 使用部署ID进行删除
	}

	public static class ProcessDefintionQueryConds {
		private Map<ProcessDefinitionCondsType, String> queryConds = new HashMap<ProcessDefinitionCondsType, String>();
		private PageInfo pageInfo;
		private Map<ProcessDefinitionQueryOrderType, ProcessDefintionProperty> orders = new HashMap<ProcessDefinitionQueryOrderType, ProcessDefintionProperty>();

		public Map<ProcessDefinitionCondsType, String> getQueryConds() {
			return queryConds;
		}

		public Map<ProcessDefinitionQueryOrderType, ProcessDefintionProperty> getOrders() {
			return orders;
		}

		public void addCond(ProcessDefinitionCondsType type, String value) {
			queryConds.put(type, value);
		}

		public void setPageInfo(PageInfo pageInfo) {
			this.pageInfo = pageInfo;
		}

		public PageInfo getPageInfo() {
			return pageInfo;
		}

		public void addOrder(ProcessDefinitionQueryOrderType type,
				ProcessDefintionProperty value) {
			orders.put(type, value);
		}
	}

	public static enum ProcessDefintionProperty {
		PROPERTY_ID("idProperty.stringValue"), PROPERTY_KEY(
				"keyProperty.stringValue"), PROPERTY_NAME(
				"idProperty.objectName"), PROPERTY_VERSION(
				"versionProperty.longValue"), PROPERTY_DEPLOYMENT_TIMESTAMP(
				"deployment.timestamp");

		private String value;

		private ProcessDefintionProperty(String value) {
			this.value = value;
		}

		public String getValue() {
			return value;
		}
	}

	public static enum TaskProperty {
		PROPERTY_NAME("name"), PROPERTY_ASSIGNEE("assignee"), PROPERTY_CREATEDATE(
				"createTime"), PROPERTY_DUEDATE("duedate"), PROPERTY_PRIORITY(
				"priority"), PROPERTY_PROGRESS("progress");

		private String value;

		private TaskProperty(String value) {
			this.value = value;
		}

		public String getValue() {
			return value;
		}
	}

	public static enum ProcessDefinitionCondsType {
		ID("idProperty.stringValue") {
			@Override
			public void setCond(ProcessDefinitionQuery processDefinitionQuery,
					String value) {
				processDefinitionQuery.processDefinitionId(this.getValue());
			}
		},
		KEY("keyProperty.stringValue") {
			@Override
			public void setCond(ProcessDefinitionQuery processDefinitionQuery,
					String value) {
				processDefinitionQuery.processDefinitionKey(value);
			}
		},
		NAME("idProperty.objectName") {
			@Override
			public void setCond(ProcessDefinitionQuery processDefinitionQuery,
					String value) {
				processDefinitionQuery.processDefinitionName(this.getValue());
			}
		},
		NAMELIKE("idProperty.objectNameLIKE") {
			@Override
			public void setCond(ProcessDefinitionQuery processDefinitionQuery,
					String value) {
				processDefinitionQuery.processDefinitionNameLike(value);
			}
		};

		private String value;

		public String getValue() {
			return value;
		}

		private ProcessDefinitionCondsType(String value) {
			this.value = value;
		}

		public abstract void setCond(
				ProcessDefinitionQuery processDefinitionQuery, String value);
	}

	public static class TaskQueryConds {
		private Map<TaskCondsType, String> queryConds = new HashMap<TaskCondsType, String>();
		private PageInfo pageInfo;
		private Map<TaskQueryOrderType, TaskProperty> orders = new HashMap<TaskQueryOrderType, TaskProperty>();

		public Map<TaskCondsType, String> getQueryConds() {
			return queryConds;
		}

		public Map<TaskQueryOrderType, TaskProperty> getOrders() {
			return orders;
		}

		public void addCond(TaskCondsType type, String value) {
			queryConds.put(type, value);
		}

		public void addOrder(TaskQueryOrderType orderType, TaskProperty value) {
			orders.put(orderType, value);
		}

		public void setPageInfo(PageInfo pageInfo) {
			this.pageInfo = pageInfo;
		}

		public PageInfo getPageInfo() {
			return pageInfo;
		}

	}

	public static enum TaskCondsType {
		ACTIVITYNAME("activityname") {
			@Override
			public void setCond(TaskQuery taskQuery, String value) {
				taskQuery.activityName(this.getValue());
			}
		},
		ASSIGNEE("assignee") {
			@Override
			public void setCond(TaskQuery taskQuery, String value) {
				taskQuery.assignee(value);
			}
		},
		CANDIDATE("candidate") {
			@Override
			public void setCond(TaskQuery taskQuery, String value) {
				taskQuery.candidate(value);
			}
		},
		EXECUTIONID("executionid") {
			@Override
			public void setCond(TaskQuery taskQuery, String value) {
				taskQuery.executionId(value);
			}
		},
		PROCESSINSTANCEID("processinstanceid") {
			@Override
			public void setCond(TaskQuery taskQuery, String value) {
				taskQuery.processInstanceId(value);
			}
		},
		PROCESSDEFINITIONID("processdefinitionid") {
			@Override
			public void setCond(TaskQuery taskQuery, String value) {
				taskQuery.processDefinitionId(value);
			}
		},
		ORDERASC("orderasc") {
			@Override
			public void setCond(TaskQuery taskQuery, String value) {
				taskQuery.orderAsc(value);
			}
		},
		ORDERDESC("orderdesc") {
			@Override
			public void setCond(TaskQuery taskQuery, String value) {
				taskQuery.orderDesc(value);
			}
		};

		private String value;

		public String getValue() {
			return value;
		}

		private TaskCondsType(String value) {
			this.value = value;
		}

		public abstract void setCond(TaskQuery taskQuery, String value);
	}

	public static enum ProcessDefinitionQueryOrderType {
		ORDERASC {

			@Override
			public void setOrder(ProcessDefinitionQuery processDefinitionQuery,
					ProcessDefintionProperty property) {
				processDefinitionQuery.orderAsc(property.getValue());
			}
		},
		ORDERDESC {

			@Override
			public void setOrder(ProcessDefinitionQuery processDefinitionQuery,
					ProcessDefintionProperty property) {
				processDefinitionQuery.orderDesc(property.getValue());
			}
		};
		public abstract void setOrder(
				ProcessDefinitionQuery processDefinitionQuery,
				ProcessDefintionProperty property);
	}

	public static enum TaskQueryOrderType {
		ORDERASC {

			@Override
			public void setOrder(TaskQuery taskQuery, TaskProperty property) {
				taskQuery.orderAsc(property.getValue());
			}
		},
		ORDERDESC {

			@Override
			public void setOrder(TaskQuery taskQuery, TaskProperty property) {
				taskQuery.orderDesc(property.getValue());
			}
		};
		public abstract void setOrder(TaskQuery processDefinitionQuery,
				TaskProperty property);
	}

	public static class PageInfo {
		private int maxResults;
		private int firstResult;

		public int getMaxResults() {
			return maxResults;
		}

		public void setMaxResults(int maxResults) {
			this.maxResults = maxResults;
		}

		public int getFirstResult() {
			return firstResult;
		}

		public void setFirstResult(int firstResult) {
			this.firstResult = firstResult;
		}
	}

}
